#include "ReactorAcceptor.h"

#include "./Session.h"
#include "./SessionManager.h"

namespace Reactor
{
	template <class SocketReactorDispatcher>
	ReactorAcceptor<SocketReactorDispatcher>::ReactorAcceptor(Poco::Net::ServerSocket& socket, std::shared_ptr<ServerFactory> _serverFactory, const SessionOp& _sessionop) :
		_socket(socket),
		_pReactor(nullptr), _sessionop(_sessionop), _serverFactory(_serverFactory)
	{
	}

	template <class SocketReactorDispatcher>
	ReactorAcceptor<SocketReactorDispatcher>::ReactorAcceptor(Poco::Net::ServerSocket& socket, std::shared_ptr<ServerFactory> _serverFactory, Poco::Net::SocketReactor& reactor, const SessionOp& _sessionop) :
		_socket(socket),
		_pReactor(&reactor), _sessionop(_sessionop), _serverFactory(_serverFactory)
	{
		_pReactor->addEventHandler(_socket, Observer(*this, &ReactorAcceptor::onAccept));
	}

	template <class SocketReactorDispatcher>
	ReactorAcceptor<SocketReactorDispatcher>::~ReactorAcceptor()
	{
		try
		{
			if (_pReactor)
			{
				_pReactor->removeEventHandler(_socket, Observer(*this, &ReactorAcceptor::onAccept));
			}
		}
		catch (...)
		{
			poco_unexpected();
		}
	}

	template <class SocketReactorDispatcher>
	void ReactorAcceptor<SocketReactorDispatcher>::setReactor(Poco::Net::SocketReactor& reactor)
	{
		registerAcceptor(reactor);
	}

	template <class SocketReactorDispatcher>
	void ReactorAcceptor<SocketReactorDispatcher>::registerAcceptor(Poco::Net::SocketReactor& reactor)
	{
		_pReactor = &reactor;
		if (!_pReactor->hasEventHandler(_socket, Observer(*this, &ReactorAcceptor::onAccept)))
		{
			_pReactor->addEventHandler(_socket, Observer(*this, &ReactorAcceptor::onAccept));
		}
	}

	template <class SocketReactorDispatcher>
	void ReactorAcceptor<SocketReactorDispatcher>::unregisterAcceptor()
	{
		if (_pReactor)
		{
			_pReactor->removeEventHandler(_socket, Observer(*this, &ReactorAcceptor::onAccept));
		}
	}

	template <class SocketReactorDispatcher>
	void ReactorAcceptor<SocketReactorDispatcher>::onAccept(Poco::Net::ReadableNotification* pNotification)
	{
		pNotification->release();
		Poco::Net::StreamSocket sock = _socket.acceptConnection();
		_pReactor->wakeUp();
		createServiceHandler(sock);
	}

	template<class SocketReactorDispatcher>
	inline SocketReactorDispatcher* ReactorAcceptor<SocketReactorDispatcher>::reactorDispatcher() const
	{
		return _pSocketReactorDispatcher;
	}

	template<class SocketReactorDispatcher>
	inline void ReactorAcceptor<SocketReactorDispatcher>::setSocketReactorDispatcher(std::shared_ptr<SocketReactorDispatcher> dispatcher)
	{
		if (!dispatcher)
		{
			return;
		}
		_pSocketReactorDispatcher = dispatcher;
	}

	template <class SocketReactorDispatcher>
	void ReactorAcceptor<SocketReactorDispatcher>::createServiceHandler(Poco::Net::StreamSocket& socket)
	{
		std::shared_ptr<SubReactor> _nextReactor = _pSocketReactorDispatcher->reactor(&socket);
		if (!_nextReactor)
		{
			return;
		}
		SessionAutoPtr session = _serverFactory->createSession(socket, _sessionop);
		SessionManager::instance()->addSession(session->self());
		session->setReactor(*_nextReactor);
		std::cout << "********reactor......" << _nextReactor << std::endl;
	}

	template <class SocketReactorDispatcher>
	Poco::Net::SocketReactor* ReactorAcceptor<SocketReactorDispatcher>::reactor()
	{
		return _pReactor;
	}

	template <class SocketReactorDispatcher>
	Poco::Net::Socket& ReactorAcceptor<SocketReactorDispatcher>::socket()
	{
		return _socket;
	}
}